package mint.modules.generator.expression;

import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

import org.antlr.runtime.tree.Tree;

import mint.modules.generator.CounterManager;
import mint.modules.generator.Scope;
import mint.modules.type.Type;

public class RelationalExprNode extends Expression {
	private Expression left, right;
	private Type type;
	private int line;
	private List<String> errors;
	private String operator;

	public RelationalExprNode(Scope theParent, ExpressionType exprType, Tree relationalTree) {
		super(theParent, exprType);
		
		type = null;
		line = relationalTree.getLine();
		errors = new ArrayList<String>();
		operator = null;
		
		if (relationalTree.getText().equals("<") || 
			relationalTree.getText().equals(">") || 
			relationalTree.getText().equals("<=") ||
			relationalTree.getText().equals(">="))
		{
			left = new RelationalExprNode(theParent, exprType, relationalTree.getChild(0));
			right = new AdditiveExprNode(theParent, exprType, relationalTree.getChild(1));
			operator = relationalTree.getText();
		}
		else
		{
			left = new AdditiveExprNode(theParent, exprType, relationalTree);
			right = null;
		}
	}

	@Override
	public void testSemantic() {
		left.testSemantic();
		type = left.getType();
		
		if (right != null)
		{
			if (getExpressionType() != ExpressionType.Right)
				errors.add(line + ": " + operator + " must be used on the right side of a expression");
			
			right.testSemantic();
			type = Type.booleanType;
			
			Type typeLeft = left.getType();
			Type typeRight = right.getType();			
			
			if (operator.equals("<") || operator.equals(">")
				|| operator.equals("<=") || operator.equals(">="))
			{
				if (typeLeft.equals(Type.intType) || typeLeft.equals(Type.floatType))
				{
					if (!(typeRight.equals(Type.intType) || typeRight.equals(Type.floatType)))									
						errors.add(line + ": " + operator + " must be used on integer or float expressions");
					
				} else
					errors.add(line + ": " + operator + " must be used on integer or float expressions");
			}  else
				errors.add(line + ": " + operator + " must be used on integer expressions");			
		}
	}

	@Override
	public List<String> getSemanticErrors() {
		errors.addAll(left.getSemanticErrors());
		if (right != null)
			errors.addAll(right.getSemanticErrors());
		return errors;
	}

	@Override
	public void emit(Formatter output) {
		left.emit(output);
		
		if (operator != null)
		{
			Type typeLeft = left.getType();
			Type typeRight = right.getType();
			
			if (typeLeft.equals(Type.intType))
			{
				if (typeRight.equals(Type.intType))
				{
					right.emit(output);
					output.format("isub\n");
				}
				else if (typeRight.equals(Type.floatType))
				{
					output.format("i2f\n");
					right.emit(output);
					output.format("fsub\n");
					output.format("f2i\n");
				}
			}
			else if (typeLeft.equals(Type.floatType))
			{
				right.emit(output);
				if (typeRight.equals(Type.intType))
					output.format("i2f\n");
				output.format("fsub\n");
				output.format("f2i\n");
			}
			
			String label1 = CounterManager.getInstance().generate("rel");
			String label2 = CounterManager.getInstance().generate("rel");
			String label3 = CounterManager.getInstance().generate("rel");
			
			if (operator.equals("<"))
				output.format("iflt %s\n", label1);				
			else if (operator.equals(">"))
				output.format("ifgt %s\n", label1);
			else if (operator.equals("<="))
				output.format("ifle %s\n", label1);
			else if (operator.equals(">="))
				output.format("ifge %s\n", label1);
			else
				output.format("iflt %s\n", label1);
				
			output.format("goto %s\n", label2);
			output.format("%s:\n", label1);			
			output.format("iconst_1\n");
			output.format("goto %s\n", label3);
			output.format("%s:\n", label2);			
			output.format("iconst_0\n");
			output.format("%s:\n", label3);
		}
	}

	@Override
	public int getLine() {
		return line;
	}

	@Override
	public Type getType() {		
		return type;
	}

	@Override
	public void leftEmit(Formatter output) {
		left.leftEmit(output);		
	}
}
